﻿using AutoMapper;
using IdentityServer4.EntityFramework.Entities;
using System.Security.Claims;
namespace EMall.IdentityService.IdentityServers
{
    public class IdentityServerProfile : Profile
    {
        public IdentityServerProfile()
        {
            #region client
            CreateMap<ClientProperty, KeyValuePair<string, string>>()
                .ReverseMap();
            CreateMap<Client, IdentityServer4.Models.Client>()
                .ForMember(dest => dest.ProtocolType, opt => opt.Condition(srs => srs != null))
                .ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms))
                .ReverseMap()
                .ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms));
            CreateMap<ClientCorsOrigin, string>()
                .ConstructUsing(src => src.Origin)
                .ReverseMap()
                .ForMember(dest => dest.Origin, opt => opt.MapFrom(src => src));
            CreateMap<ClientIdPRestriction, string>()
                .ConstructUsing(src => src.Provider)
                .ReverseMap()
                .ForMember(dest => dest.Provider, opt => opt.MapFrom(src => src));
            CreateMap<ClientClaim, IdentityServer4.Models.ClientClaim>(MemberList.None)
                .ConstructUsing(src => new IdentityServer4.Models.ClientClaim(src.Type, src.Value, ClaimValueTypes.String))
                .ReverseMap();
            CreateMap<ClientScope, string>()
                .ConstructUsing(src => src.Scope)
                .ReverseMap()
                .ForMember(dest => dest.Scope, opt => opt.MapFrom(src => src));
            CreateMap<ClientPostLogoutRedirectUri, string>()
                .ConstructUsing(src => src.PostLogoutRedirectUri)
                .ReverseMap()
                .ForMember(dest => dest.PostLogoutRedirectUri, opt => opt.MapFrom(src => src));
            CreateMap<ClientRedirectUri, string>()
                .ConstructUsing(src => src.RedirectUri)
                .ReverseMap()
                .ForMember(dest => dest.RedirectUri, opt => opt.MapFrom(src => src));
            CreateMap<ClientGrantType, string>()
                .ConstructUsing(src => src.GrantType)
                .ReverseMap()
                .ForMember(dest => dest.GrantType, opt => opt.MapFrom(src => src));
            CreateMap<ClientSecret, IdentityServer4.Models.Secret>(MemberList.Destination)
                .ForMember(dest => dest.Type, opt => opt.Condition(srs => srs != null))
                .ReverseMap();
            #endregion
            #region identityresource
            CreateMap<IdentityResourceProperty, KeyValuePair<string, string>>()
                .ReverseMap();
            CreateMap<IdentityResource, IdentityServer4.Models.IdentityResource>(MemberList.Destination)
                .ConstructUsing(src => new IdentityServer4.Models.IdentityResource())
                .ReverseMap();
            CreateMap<IdentityResourceClaim, string>()
               .ConstructUsing(x => x.Type)
               .ReverseMap()
               .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src));
            #endregion
            #region apiscope
            CreateMap<ApiScopeProperty, KeyValuePair<string, string>>()
                .ReverseMap();
            CreateMap<ApiScopeClaim, string>()
               .ConstructUsing(x => x.Type)
               .ReverseMap()
               .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src));
            CreateMap<ApiScope, IdentityServer4.Models.ApiScope>(MemberList.Destination)
                .ConstructUsing(src => new IdentityServer4.Models.ApiScope())
                .ForMember(x => x.Properties, opts => opts.MapFrom(x => x.Properties))
                .ForMember(x => x.UserClaims, opts => opts.MapFrom(x => x.UserClaims))
                .ReverseMap();
            #endregion
            #region apiresource
            CreateMap<ApiResourceProperty, KeyValuePair<string, string>>()
                .ReverseMap();
            CreateMap<ApiResource, IdentityServer4.Models.ApiResource>(MemberList.Destination)
                .ConstructUsing(src => new IdentityServer4.Models.ApiResource())
                .ForMember(x => x.ApiSecrets, opts => opts.MapFrom(x => x.Secrets))
                .ForMember(x => x.AllowedAccessTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedAccessTokenSigningAlgorithms))
                .ReverseMap()
                .ForMember(x => x.AllowedAccessTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedAccessTokenSigningAlgorithms));
            CreateMap<ApiResourceClaim, string>()
                .ConstructUsing(x => x.Type)
                .ReverseMap()
                .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src));
            CreateMap<ApiResourceSecret, IdentityServer4.Models.Secret>(MemberList.Destination)
                .ForMember(dest => dest.Type, opt => opt.Condition(srs => srs != null))
                .ReverseMap();
            CreateMap<ApiResourceScope, string>()
                .ConstructUsing(x => x.Scope)
                .ReverseMap()
                .ForMember(dest => dest.Scope, opt => opt.MapFrom(src => src));
            #endregion
        }
        public class AllowedSigningAlgorithmsConverter :
            IValueConverter<ICollection<string>, string>,
            IValueConverter<string, ICollection<string>>
        {
            public static AllowedSigningAlgorithmsConverter Converter = new AllowedSigningAlgorithmsConverter();
            public string Convert(ICollection<string> sourceMember, ResolutionContext context)
            {
                if (sourceMember == null || !sourceMember.Any())
                {
                    return null;
                }
                return sourceMember.Aggregate((x, y) => $"{x},{y}");
            }
            public ICollection<string> Convert(string sourceMember, ResolutionContext context)
            {
                var list = new HashSet<string>();
                if (!String.IsNullOrWhiteSpace(sourceMember))
                {
                    sourceMember = sourceMember.Trim();
                    foreach (var item in sourceMember.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct())
                    {
                        list.Add(item);
                    }
                }
                return list;
            }
        }
    }
    public static class IdentityServerMappers
    {
        static IdentityServerMappers()
        {
            Mapper = new MapperConfiguration(cfg => cfg.AddProfile<IdentityServerProfile>()).CreateMapper();
        }
        internal static IMapper Mapper { get; }
        public static IdentityServer4.Models.IdentityResource ToModel(this IdentityResource entity)
        {
            return entity == null ? null : Mapper.Map<IdentityServer4.Models.IdentityResource>(entity);
        }
        public static IdentityResource ToEntity(this IdentityServer4.Models.IdentityResource model)
        {
            return model == null ? null : Mapper.Map<IdentityResource>(model);
        }

        public static IdentityServer4.Models.ApiResource ToModel(this ApiResource entity)
        {
            return entity == null ? null : Mapper.Map<IdentityServer4.Models.ApiResource>(entity);
        }
        public static ApiResource ToEntity(this IdentityServer4.Models.ApiResource model)
        {
            return model == null ? null : Mapper.Map<ApiResource>(model);
        }

        public static IdentityServer4.Models.ApiScope ToModel(this ApiScope entity)
        {
            return entity == null ? null : Mapper.Map<IdentityServer4.Models.ApiScope>(entity);
        }
        public static ApiScope ToEntity(this IdentityServer4.Models.ApiScope model)
        {
            return model == null ? null : Mapper.Map<ApiScope>(model);
        }

        public static IdentityServer4.Models.Client ToModel(this Client entity)
        {
            return entity == null ? null : Mapper.Map<IdentityServer4.Models.Client>(entity);
        }
        public static Client ToEntity(this IdentityServer4.Models.Client model)
        {
            return model == null ? null : Mapper.Map<Client>(model);
        }
    }
}
